/////////////////////////////////////////////////////////////////////////////
// Filename: Object.cpp
/////////////////////////////////////////////////////////////////////////////

#include "Object.h"
#include "Draw_triangle.h"
#include "ShadingModels.h"
#include <GL/glut.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
using namespace std;


void Object::transform(Matrix4 m){
	for(int i=0; i<no_vertices; i++){
		vertices[i].transform(m);
	}
	for(int i=0; i<no_faces; i++){
		faces[i].transform(m);
	}

	view_anisotropy_origin=m*anisotropy_origin;
	view_anisotropy_axis=m*Vector3h(anisotropy_axis,0); //Not affected by translations
	view_anisotropy_axis.normalize();

}

void Object::ShadeFaces(vector<Light> light_list){
	for(int i=0; i<no_faces; i++){
		faces[i].illumination=Color(0,0,0);
		Vector3 anisotropy_direction=view_anisotropy_axis^(vertices[faces[i].a].view_position - view_anisotropy_origin); //assignment 3
		for(unsigned int j=0; j<light_list.size(); j++){
			faces[i].illumination+=AnisotropicPhong(vertices[faces[i].a].view_position,
											   faces[i].view_normal, 
											   anisotropy_direction,
											   light_list[j]);
		}
	}
}
	
void Object::ShadeVertices(vector<Light> light_list){
	for(int i=0; i<no_vertices; i++){
		vertices[i].illumination=Color(0,0,0);
		Vector3 anisotropy_direction=view_anisotropy_axis^(vertices[i].view_position - view_anisotropy_origin); //assignment 3
		for(unsigned int j=0; j<light_list.size(); j++){
			vertices[i].illumination+=AnisotropicPhong(vertices[i].view_position,
												  vertices[i].view_normal, 
												  anisotropy_direction,
												  light_list[j]);
		}
	}
}

void Object::Display(Matrix4 view_matrix, vector<Light> light_list, int shading_type){

	Matrix4 model_view_matrix=view_matrix*model_matrix;

	//Transform object to camera coordinates
	transform(model_view_matrix);

	//Transform light sources to camera coordinates
	for(unsigned int i=0; i<light_list.size(); i++){
		light_list[i].position = view_matrix*light_list[i].position;
	}


	switch (shading_type){
		case WIREFRAME_SHADING:
			for(int i=0; i<no_faces; i++){
				empty_triangle(vertices[faces[i].a].view_position,
							   vertices[faces[i].b].view_position, 
							   vertices[faces[i].c].view_position, 
							   Color(1,1,0));
			}
			break;
		case FLAT_SHADING:
			ShadeFaces(light_list);
			for(int i=0; i<no_faces; i++){
				solid_triangle(vertices[faces[i].a].view_position,
							   vertices[faces[i].b].view_position, 
							   vertices[faces[i].c].view_position, 
							   faces[i].illumination);
			}
			break;
		case SMOOTH_SHADING:
			ShadeVertices(light_list);
			for(int i=0; i<no_faces; i++){
				interp_triangle(vertices[faces[i].a].view_position,
							    vertices[faces[i].b].view_position, 
							    vertices[faces[i].c].view_position, 
							    vertices[faces[i].a].illumination,
							    vertices[faces[i].b].illumination,
							    vertices[faces[i].c].illumination);
			}
			break;
	}

}

void Object::Load_obj(const char* filename){
	cout<<"Loading file: "<<filename<<endl;

	ifstream infile(filename);
	if (!infile.good()) {
		cerr << "Failed opening file " << filename << endl;      
		exit(1);
	}

	vertices.clear();
	faces.clear();
	
	string s;

	while(getline(infile, s)){
		istringstream stream;
		stream.str(s);
		char c;
		stream>>c;

		//Vertex
		if(c=='v'){
			float x,y,z;
			stream>>x>>y>>z;
			vertices.push_back(Vertex(x,y,z));
		}

		//Face
		if(c=='f'){
			int a,b,c;
			stream>>a>>b>>c;
			faces.push_back(Triangle(a-1,b-1,c-1));
		}
	}

	no_vertices=(int)vertices.size();
	no_faces=(int)faces.size();

	cout<<"Number of vertices: "<<no_vertices<<endl;
	cout<<"Number of faces: "<<no_faces<<endl;


	//Reset all vertex normals
	for(int i=0; i<no_vertices; i++){
		vertices[i].normal=Vector3(0,0,0);
	}


	for(int i=0; i<no_faces; i++){
		//Calculate face normal
		Vector3 p1=vertices[faces[i].a].position;
		Vector3 p2=vertices[faces[i].b].position;
		Vector3 p3=vertices[faces[i].c].position;
		faces[i].normal=(p2-p1)^(p3-p1);
		faces[i].normal.normalize();

		//A vertex normal is the average normal of all triangles sharing the vertex
		vertices[faces[i].a].normal+= faces[i].normal;
		vertices[faces[i].b].normal+= faces[i].normal;
		vertices[faces[i].c].normal+= faces[i].normal;
	}

	//Normalize all vertex normals
	for(int i=0; i<no_vertices; i++){
		vertices[i].normal.normalize();
	}

}

/////////////////////////////////////////////////////////////////////////////
//                               END OF FILE                               //
/////////////////////////////////////////////////////////////////////////////